package logic

import (
	"context"
	"crypto/md5"
	"fmt"
	"grpc.getaway.adminspro.padmins.com/internal/rpc/utils/database"
	"grpc.getaway.adminspro.padmins.com/pkg/config/businessError"
	"grpc.getaway.adminspro.padmins.com/pkg/libs/utils"
	"math/rand"
	"strconv"
	"time"
)

func Login(ctx context.Context, account string, password string) (map[string]interface{}, *businessError.ErrorInfo) {
	if account == "" {
		return nil, businessError.AuthAccountEmpty
	}

	if password == "" {
		return nil, businessError.AuthPasswordEmpty
	}

	Db := database.Db.GetDefaultDb(ctx)

	row, dbErr := Db.Find("select * from admin where email=? or username=?", account, account)

	if dbErr != nil {
		return nil, businessError.DbError(dbErr)
	}

	if row == nil {
		return nil, businessError.AuthUserNotExits
	}

	loc, _ := time.LoadLocation("Local")
	updateTime, _ := time.ParseInLocation(utils.DateLayout("Y-m-d H:i:s"), row["update_time"].(string), loc)

	if row["loginfailure"].(int64) >= 10 && updateTime.Unix() >= time.Now().Unix()-300 {
		return nil, businessError.ErrorfByErrorInfo(businessError.AuthLoginFailureLock, row["loginfailure"])
	}

	if row["password"].(string) != fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%x", md5.Sum([]byte(password)))+row["salt"].(string)))) {
		row["update_time"] = utils.Date("Y-m-d H:i:s")
		row["loginfailure"] = row["loginfailure"].(int64) + 1

		Result, dbErr := Db.Execute("update admin set loginfailure=?,update_time=? where id=?", row["loginfailure"], row["update_time"], row["id"])

		if dbErr != nil {
			return nil, businessError.AuthLoginFail
		}

		RowsAffected, e := Result.RowsAffected()

		if e != nil || RowsAffected <= 0 {
			return nil, businessError.AuthLoginFail
		}

		loginfailure := 10 - row["loginfailure"].(int64)

		if loginfailure <= 0 {
			return nil, businessError.ErrorfByErrorInfo(businessError.AuthLoginFailureLock, 10)
		}

		if loginfailure <= 3 {
			return nil, businessError.ErrorfByErrorInfo(businessError.AuthLoginFailure, loginfailure)
		}
		return nil, businessError.AuthAccountPasswordError
	}

	if row["status"].(int64) == 0 {
		return nil, businessError.AuthAdminForbidden
	}

	row["login_time"] = utils.Date("Y-m-d H:i:s")
	row["update_time"] = utils.Date("Y-m-d H:i:s")
	row["loginfailure"] = int64(0)
	rand.Seed(time.Now().UnixNano())
	row["token"] = utils.Md5(row["login_time"].(string) + strconv.FormatInt(int64(rand.Intn(99999-10000)+10000), 10))
	Result, dbErr := Db.Execute(
		"update admin set login_time=?,token=?,token_expiry_time=?,update_time=?,loginfailure=? where id=?",
		row["login_time"],
		row["token"],
		row["token_expiry_time"],
		row["update_time"],
		row["loginfailure"],
		row["id"],
	)
	if dbErr != nil {
		return nil, businessError.AuthLoginFail
	}

	RowsAffected, e := Result.RowsAffected()

	if e != nil || RowsAffected <= 0 {
		return nil, businessError.AuthLoginFail
	}

	return row, nil
}
